<template>
  <div style="border: 1px solid red">
    <Toolbar style="border-bottom: 1px solid #ccc" :editor="editorRef" :defaultConfig="toolbarConfig" :mode="mode" />
    <Editor style="height: 400px; overflow-y: hidden" v-model="valueHtml" :defaultConfig="editorConfig" :mode="mode"
      @onChange="handleChange" @onCreated="handleCreated" />
  </div>
</template>

<script setup lang='ts'>
import "@wangeditor/editor/dist/css/style.css"; // 引入 css
import { getWangEditor } from "@/api/other";
import { onBeforeUnmount, ref, shallowRef, watch, nextTick } from "vue";
import { Editor, Toolbar } from "@wangeditor/editor-for-vue";
import { IEditorConfig } from "@wangeditor/editor";
import { SlateElement } from "@wangeditor/editor";
import { ExperienceSaveFilesApi, ExperienceDelFilesApi } from "@/api/Experience/ExperienceList";
import { rejects } from "assert";
type InsertFnType = (url: string, alt?: string, href?: string) => void;
type ImageElement = SlateElement & {
  src: string;
  alt: string;
  url: string;
  href: string;
};
// 1 数据进来监听 2 数据改变监听 3 离开数据清除 ->图片上传处理
// 编辑器实例，必须用 shallowRef
const emit = defineEmits(["changeText"]);
const editorRef = shallowRef();
// 内容 HTML 数据应该怎么回显
const valueHtml = ref();
const mode = ref("simple");
const toolbarConfig: Partial<any> = {
  excludeKeys: ["insertLink", "insertVideo"],
};

const tempImageObj: {
  insertImages: ImageElement[],
  allImages: ImageElement[],
} = {
  insertImages: [],
  allImages: []
}

const editorConfig = {
  placeholder: "请输入内容...",
  MENU_CONF: {},
};
// 上传图片
editorConfig.MENU_CONF["uploadImage"] = {
  // 自定义上传
  async customUpload(file: File, insertFn: InsertFnType) {
    const t2: any = new Date().getTime(); // TS 语法
    const formData = new FormData();
    formData.append('files', file);
    formData.append('timestamp', t2);
    const res = await ExperienceSaveFilesApi(formData);
    // 传res.data.url 里面最后一个/后面的名字---  也就是以下字符串 str
    const str = res.data.url.split('/').slice(-1).toString()
    // 后端要这个str
    const arr: any = await getWangEditor(res.data.url);
    const url = window.webkitURL.createObjectURL(
      new Blob([arr], { type: "image/png" })
    );
    // file 即选中的文件
    // 自己实现上传，并得到图片 url alt href
    // 最后插入图片
    const href = res.data.url;
    const alt = "加载失败!";
    insertFn(url, alt, href);
  },
};
// 删除图片
editorConfig.MENU_CONF["insertImage"] = {
  onInsertedImage(imageNode: ImageElement | null) {
    // TS 语法
    // onInsertedImage(imageNode) {
    console.log("-----", imageNode);
    // JS 语法
    if (imageNode == null) return;
    console.log(imageNode);

    const { src, alt, url, href } = imageNode;
    console.log("inserted image", src, alt, url, href);
    tempImageObj.insertImages.push(imageNode)
  },
};

const handleCreated = (editor) => {
  editorRef.value = editor; // 记录 editor 实例，重要！
  // console.log(editor.getAllMenuKeys());
};
// 数据变化
const handleChange = (editor) => {
  console.log(editor.getHtml());
};

/**
 * 在点击确定的时候 调用这个方法
 */
const delImages = async () => {
  tempImageObj.allImages = editorRef.value.getElemsByType('image');
  console.log('tempImageObj', tempImageObj);
  const { allImages = [], insertImages = [] } = tempImageObj
  // 在这里删除 不同的，这个方法，在编辑开发中可能 inster 这个数组 不会更新 需要 修改了，代码 刷新页面 才能正常用， 切记切记切记
  const list = insertImages.filter(f => {
    const item = allImages.find(af => af.href === f.href)
    return !!!item
  })
  console.log('需要删除的 ', list)
  for (let i = 0; i < list.length; i++) {
    const file = list[i];
    // 循环删除所有的 删除成功和失败，这个不是重要的
    const res = await ExperienceDelFilesApi({ fileName: file.href })
  }
}
// 组件销毁时，也及时销毁编辑器
onBeforeUnmount(() => {
  const editor = editorRef.value;
  if (editor == null) return;
  // valueHtml.value=null
  editor.destroy();
});
watch(
  () => valueHtml.value,
  (newValue, oldValue) => {
    console.log('-----------------', newValue);
    console.log('+++++++++++++', oldValue);
    // 数据改变就传递
    if (newValue !== oldValue) {
      emit("changeText", newValue);
    }
  },
  {
    immediate: true,
    deep: true,
  }
);
defineExpose({
  valueHtml,
  delImages // 导出了这个方法，
});
</script>
<style scoped lang='scss'></style>